#pragma once
#include <functional>

namespace xyx
{
	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* p)
			:_ptr(p)
		{}

		auto_ptr(auto_ptr<T>& ap)
			:_ptr(ap._ptr)
		{
			ap._ptr = nullptr;
		}

		auto_ptr<T>& operator=(auto_ptr<T>& ap)
		{
			_ptr = ap._ptr;
			ap._ptr = nullptr;

			return *this;
		}

		~auto_ptr()
		{
			delete _ptr;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
	
	template<class T>
	struct Default_Delete
	{
		void operator()(T* ptr) { delete ptr; }
	};

	template<class T, class D = Default_Delete<T>>
	class unique_ptr
	{
	public:
		unique_ptr(T* p, D d = Default_Delete<T>())
			:_ptr(p)
			,_d(d)
		{}

		unique_ptr(unique_ptr<T, D>& up) = delete;
		unique_ptr<T, D>& operator=(unique_ptr<T, D>& up) = delete;

		~unique_ptr()
		{
			_d(_ptr);
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
		D _d;
	};

	template<class T>
	class shared_ptr
	{
	public:
		template<class D>
		shared_ptr(T* p, D d)
			:_ptr(p)
			, _pCount(new int(1))
			, _pmtx(new mutex)
			,_del(d)
		{}

		shared_ptr(T* p)
			:_ptr(p)
			, _pCount(new int(1))
			,_pmtx(new mutex)
		{}

		shared_ptr(shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			,_pCount(sp._pCount)
			,_pmtx(sp._pmtx)
		{
			AddRef();
		}

		shared_ptr<T>& operator= (shared_ptr<T>& sp)
		{
			//sp1 = sp1;
			//sp2 = sp1; 
	
			if (_ptr != sp._ptr) 
			{
				Release();
				_ptr = sp._ptr;
				_pCount = sp._pCount;
				_pmtx;
				AddRef();
			}

			return *this;
		}

		~shared_ptr()
		{
			Release();
		}

		void Release()
		{
			_pmtx->lock();
			bool flag = false;
			if (--(*_pCount) == 0 && _ptr)
			{
				cout << "delete:" << _ptr << endl;
				_del(_ptr);
				delete _pCount;
				flag = true;
			}
			_pmtx->unlock();

			if (flag == true)//空间释放相应的锁也要释放
			{
				delete _pmtx;
			}
		}

		void AddRef()
		{
			//保证++操作原子性
			_pmtx->lock();
			++(*_pCount);
			_pmtx->unlock();
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		int use_count() const
		{
			return *_pCount;
		}

		T* get() const
		{
			return _ptr;
		}

	private:
		T* _ptr;
		int* _pCount;
		function<void(T*)> _del = [](T* ptr) {delete ptr; };
		mutex* _pmtx;
	};


	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr()
			:_ptr(nullptr)
		{}

		weak_ptr(shared_ptr<T>& sp)
			:_ptr(sp.get()) // 需要shared提供get方法
		{
		}

		weak_ptr<T>& operator=(shared_ptr<T>& sp)
		{
			_ptr = sp.get();

			return *this;
		}

		~weak_ptr()
		{
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
}